#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
本地Web仪表板 - 连接虚拟机Redis服务
在本地机器上运行，通过网络连接虚拟机的Redis和爬虫服务
"""

from flask import Flask, jsonify, request, render_template_string
import redis
import json
import time
from datetime import datetime
import logging
import requests

app = Flask(__name__)

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# 虚拟机服务配置
VM_CONFIG = {
    'redis_host': '192.168.88.130',  # 虚拟机IP
    'redis_port': 6379,
    'redis_db': 0,
    'redis_password': '123456',  # Redis密码
    'spider_api_port': 5000  # 虚拟机爬虫API端口
}

class RemoteDataManager:
    def __init__(self):
        self.redis_client = None
        self.connect_redis()
    
    def connect_redis(self):
        """连接虚拟机的Redis服务"""
        try:
            self.redis_client = redis.Redis(
                host=VM_CONFIG['redis_host'],
                port=VM_CONFIG['redis_port'],
                db=VM_CONFIG['redis_db'],
                password=VM_CONFIG['redis_password'],
                decode_responses=True,
                socket_timeout=10,
                socket_connect_timeout=10
            )
            self.redis_client.ping()
            logger.info("✓ 成功连接到虚拟机Redis服务")
        except Exception as e:
            logger.error(f"✗ 连接虚拟机Redis失败: {e}")
            self.redis_client = None
    
    def get_latest_prices(self, limit=50):
        """从虚拟机Redis获取最新价格数据"""
        if not self.redis_client:
            return []
        
        try:
            keys = self.redis_client.keys('cnhnb_price:*')
            if not keys:
                return []
            
            data_list = []
            for key in keys:
                try:
                    data = self.redis_client.get(key)
                    if data:
                        item = json.loads(data)
                        data_list.append(item)
                except Exception as e:
                    logger.warning(f"解析数据失败 {key}: {e}")
            
            data_list.sort(key=lambda x: x.get('timestamp', 0), reverse=True)
            return data_list[:limit]
            
        except Exception as e:
            logger.error(f"获取价格数据失败: {e}")
            return []
    
    def get_system_status(self):
        """获取系统状态"""
        status = {
            'redis_connected': False,
            'spider_running': False,
            'data_count': 0,
            'last_update': None
        }
        
        # 检查Redis连接
        try:
            if self.redis_client:
                self.redis_client.ping()
                status['redis_connected'] = True
                
                # 获取数据统计
                keys = self.redis_client.keys('cnhnb_price:*')
                status['data_count'] = len(keys)
                
                if keys:
                    # 获取最新数据时间
                    latest_key = max(keys, key=lambda k: self.redis_client.get(k))
                    latest_data = self.redis_client.get(latest_key)
                    if latest_data:
                        item = json.loads(latest_data)
                        status['last_update'] = item.get('crawl_timestamp')
        except Exception as e:
            logger.error(f"检查Redis状态失败: {e}")
        
        # 检查爬虫状态（通过API）
        try:
            response = requests.get(
                f"http://{VM_CONFIG['redis_host']}:{VM_CONFIG['spider_api_port']}/api/health",
                timeout=5
            )
            if response.status_code == 200:
                status['spider_running'] = True
        except Exception as e:
            logger.debug(f"爬虫API检查失败: {e}")
        
        return status

# 全局数据管理器
data_manager = RemoteDataManager()

@app.route('/')
def index():
    return render_template_string('''
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>惠农网农产品价格实时监控 - 本地版</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
    <style>
        body { 
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); 
            min-height: 100vh; 
            font-family: 'Microsoft YaHei', sans-serif;
        }
        .container { 
            background: rgba(255,255,255,0.95); 
            border-radius: 20px; 
            margin: 20px; 
            padding: 30px; 
            box-shadow: 0 10px 30px rgba(0,0,0,0.1);
        }
        .header { 
            text-align: center; 
            margin-bottom: 30px; 
            color: #2c3e50; 
        }
        .status-card {
            background: linear-gradient(45deg, #4CAF50, #45a049);
            color: white;
            border-radius: 15px;
            padding: 20px;
            margin-bottom: 20px;
            box-shadow: 0 5px 15px rgba(0,0,0,0.1);
        }
        .status-card.error {
            background: linear-gradient(45deg, #f44336, #d32f2f);
        }
        .price-card { 
            background: white; 
            border-radius: 15px; 
            padding: 20px; 
            margin-bottom: 15px; 
            box-shadow: 0 5px 15px rgba(0,0,0,0.08);
            transition: transform 0.2s;
        }
        .price-card:hover {
            transform: translateY(-2px);
            box-shadow: 0 8px 25px rgba(0,0,0,0.12);
        }
        .product-name { 
            font-size: 1.2rem; 
            font-weight: 600; 
            color: #2c3e50; 
        }
        .price-value { 
            font-size: 1.5rem; 
            font-weight: 700; 
            color: #e74c3c; 
        }
        .location { 
            color: #3498db; 
            font-weight: 500; 
        }
        .timestamp { 
            color: #95a5a6; 
            font-size: 0.9rem; 
        }
        .refresh-btn {
            background: linear-gradient(45deg, #667eea, #764ba2);
            border: none;
            border-radius: 25px;
            padding: 10px 25px;
            color: white;
            font-weight: 600;
            transition: all 0.3s;
        }
        .refresh-btn:hover {
            transform: scale(1.05);
            box-shadow: 0 5px 15px rgba(0,0,0,0.2);
        }
        .loading {
            display: inline-block;
            width: 20px;
            height: 20px;
            border: 3px solid #f3f3f3;
            border-top: 3px solid #3498db;
            border-radius: 50%;
            animation: spin 1s linear infinite;
        }
        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1><i class="fas fa-chart-line"></i> 惠农网农产品价格实时监控</h1>
            <p>本地版 - 连接虚拟机爬虫服务</p>
        </div>
        
        <!-- 系统状态 -->
        <div id="systemStatus" class="status-card">
            <div class="row align-items-center">
                <div class="col-md-8">
                    <h5><i class="fas fa-server"></i> 系统状态</h5>
                    <div id="statusDetails">检查中...</div>
                </div>
                <div class="col-md-4 text-end">
                    <button class="refresh-btn" onclick="window.location.reload()">
                        <i class="fas fa-sync-alt"></i> 刷新
                    </button>
                </div>
            </div>
        </div>
        
        <!-- 数据统计 -->
        <div class="row mb-4">
            <div class="col-md-4">
                <div class="card text-center">
                    <div class="card-body">
                        <h5 class="card-title">数据总量</h5>
                        <h3 id="totalCount" class="text-primary">-</h3>
                    </div>
                </div>
            </div>
            <div class="col-md-4">
                <div class="card text-center">
                    <div class="card-body">
                        <h5 class="card-title">最后更新</h5>
                        <h6 id="lastUpdate" class="text-success">-</h6>
                    </div>
                </div>
            </div>
            <div class="col-md-4">
                <div class="card text-center">
                    <div class="card-body">
                        <h5 class="card-title">连接状态</h5>
                        <span id="connectionStatus" class="badge bg-secondary">检查中</span>
                    </div>
                </div>
            </div>
        </div>
        
        <!-- 价格数据 -->
        <div id="priceData">
            <div class="text-center">
                <div class="loading"></div>
                <p>正在加载数据...</p>
            </div>
        </div>
    </div>

    <script>
        async function loadSystemStatus() {
            try {
                const response = await fetch('/api/system_status');
                const data = await response.json();
                
                if (data.success) {
                    updateSystemStatus(data.data);
                }
            } catch (error) {
                console.error('加载系统状态失败:', error);
                updateSystemStatus({ error: true });
            }
        }

        function updateSystemStatus(status) {
            const statusCard = document.getElementById('systemStatus');
            const statusDetails = document.getElementById('statusDetails');
            const totalCount = document.getElementById('totalCount');
            const lastUpdate = document.getElementById('lastUpdate');
            const connectionStatus = document.getElementById('connectionStatus');
            
            if (status.error) {
                statusCard.className = 'status-card error';
                statusDetails.innerHTML = '<span class="text-white">连接虚拟机服务失败</span>';
                connectionStatus.className = 'badge bg-danger';
                connectionStatus.textContent = '连接失败';
                return;
            }
            
            // 更新状态显示
            const redisStatus = status.redis_connected ? '✓ 已连接' : '✗ 未连接';
            const spiderStatus = status.spider_running ? '✓ 运行中' : '✗ 未运行';
            
            statusDetails.innerHTML = `
                <div class="row">
                    <div class="col-md-6">
                        <i class="fas fa-database"></i> Redis: ${redisStatus}
                    </div>
                    <div class="col-md-6">
                        <i class="fas fa-spider"></i> 爬虫: ${spiderStatus}
                    </div>
                </div>
            `;
            
            // 更新统计信息
            totalCount.textContent = status.data_count;
            lastUpdate.textContent = status.last_update ? formatTime(status.last_update) : '无数据';
            
            // 更新连接状态
            if (status.redis_connected) {
                connectionStatus.className = 'badge bg-success';
                connectionStatus.textContent = '已连接';
                statusCard.className = 'status-card';
            } else {
                connectionStatus.className = 'badge bg-danger';
                connectionStatus.textContent = '未连接';
                statusCard.className = 'status-card error';
            }
        }

        async function loadData() {
            try {
                const response = await fetch('/api/latest_prices?limit=20');
                const data = await response.json();
                
                if (data.success) {
                    displayPriceData(data.data);
                } else {
                    document.getElementById('priceData').innerHTML = 
                        '<div class="text-center text-muted">加载数据失败</div>';
                }
            } catch (error) {
                console.error('加载数据失败:', error);
                document.getElementById('priceData').innerHTML = 
                    '<div class="text-center text-danger">连接错误</div>';
            }
        }

        function displayPriceData(data) {
            const container = document.getElementById('priceData');
            
            if (data.length === 0) {
                container.innerHTML = '<div class="text-center text-muted">暂无数据</div>';
                return;
            }

            const html = data.map(item => `
                <div class="price-card">
                    <div class="row align-items-center">
                        <div class="col-md-3">
                            <div class="product-name">${item.name}</div>
                        </div>
                        <div class="col-md-2">
                            <span class="price-value">${item.price_value}</span> 元/${item.unit}
                        </div>
                        <div class="col-md-3">
                            <span class="location"><i class="fas fa-map-marker-alt"></i> ${item.location}</span>
                        </div>
                        <div class="col-md-2">
                            <span class="timestamp">${formatTime(item.crawl_timestamp)}</span>
                        </div>
                        <div class="col-md-2">
                            <a href="${item.source_url}" target="_blank" class="btn btn-sm btn-outline-primary">
                                <i class="fas fa-external-link-alt"></i> 查看
                            </a>
                        </div>
                    </div>
                </div>
            `).join('');

            container.innerHTML = html;
        }

        function refreshAll() {
            loadSystemStatus();
            loadData();
        }

        function formatTime(timestamp) {
            if (!timestamp) return '';
            const date = new Date(timestamp);
            return date.toLocaleString('zh-CN');
        }

        // 页面加载时获取数据
        document.addEventListener('DOMContentLoaded', function() {
            refreshAll();
            // 每30秒自动刷新
            setInterval(refreshAll, 30000);
        });
    </script>
</body>
</html>
    ''')

@app.route('/api/latest_prices')
def api_latest_prices():
    limit = request.args.get('limit', 50, type=int)
    data = data_manager.get_latest_prices(limit)
    return jsonify({
        'success': True,
        'data': data,
        'count': len(data),
        'timestamp': datetime.now().isoformat()
    })

@app.route('/api/system_status')
def api_system_status():
    status = data_manager.get_system_status()
    return jsonify({
        'success': True,
        'data': status,
        'timestamp': datetime.now().isoformat()
    })

@app.route('/api/health')
def health_check():
    """健康检查接口"""
    redis_connected = data_manager.redis_client is not None
    try:
        if redis_connected:
            data_manager.redis_client.ping()
    except:
        redis_connected = False
    
    return jsonify({
        'status': 'healthy' if redis_connected else 'unhealthy',
        'redis_connected': redis_connected,
        'timestamp': datetime.now().isoformat()
    })

if __name__ == '__main__':
    import argparse
    
    parser = argparse.ArgumentParser(description='本地惠农网价格数据Web仪表板')
    parser.add_argument('--host', default='0.0.0.0', help='监听地址')
    parser.add_argument('--port', default=8080, type=int, help='监听端口')
    parser.add_argument('--debug', action='store_true', help='调试模式')
    
    args = parser.parse_args()
    
    print("=" * 60)
    print("本地惠农网农产品价格监控Web仪表板")
    print("=" * 60)
    print(f"虚拟机Redis地址: {VM_CONFIG['redis_host']}:{VM_CONFIG['redis_port']}")
    print(f"本地Web地址: http://localhost:{args.port}")
    print("=" * 60)
    
    app.run(
        host=args.host,
        port=args.port,
        debug=args.debug,
        threaded=True
    ) 